const config = require('./config');
const MetamonApi = require('./metamon_api');
const Web3 = require('web3');


function AutoBattle(config) {
    let self = this;
    self.config = config;
    self.metamonApi = new MetamonApi(config.address, config.chain, config.privateKey);
}

AutoBattle.prototype.run = async function () {
    let self = this;
    console.log("Raca-Metamon自动Battle脚本启动，当前账号: " + self.config.address);
    if (self.config.accessToken) {
        self.metamonApi.setAccessToken(self.config.accessToken);
    } else {
        /// 程序登录，设置accessToken
        let accessToken = await self.metamonApi.login();
        self.metamonApi.setAccessToken(accessToken);
    }


    let timeOut = self.config.loopSeconds * 1000;
    let count = 1;
    (function iterator() {
        self.runThis(count).then(() => {
            setTimeout(() => {
                count++;
                iterator();
            }, timeOut);
        }).catch((err) => {
            console.log(`error: ${err.message}`);
            console.log(err);
            setTimeout(() => {
                count++;
                iterator();
            }, timeOut);
        })
    })();
}

AutoBattle.prototype.runThis = async function (count) {
    console.log("============================程序开始第" + count + "次扫描==============================");
    let self = this;

    // 获取药水
    let potions = await self.getNft(2);
    /// 筛选是否有可攻击的宠物
    let battleQueue = self.config.battleQueue;
    let metamons = await self.getEnableMetamon(potions, battleQueue);
    if (!metamons || metamons.length <= 0) {
        console.log("当前无可攻击的元兽!");
        return;
    }
    /// 检查余额是否充足
    let isEnough = await self.isEnoughBalance(metamons);
    if (!isEnough) {
        console.log("当前账户uRaca余额不足，请先进行充值");
        return;
    }

    /// 批量打金
    let tasks = [];
    for (let i = 0; i < metamons.length; i++) {
        let metamon = metamons[i];
        let item = self.battle(metamon);
        tasks.push(item);
    }
    // await Promise.all(tasks);
    await self.batchBattle(tasks);
}

AutoBattle.prototype.isEnoughBalance = async function (metamons) {
    let self = this;
    let nft = await self.getNft(5);
    let balance = nft.bpNum || 0;
    let needBalance = 0;
    for (let i = 0; i < metamons.length; i++) {
        let metamon = metamons[i];
        let tear = metamon.tear;
        let level = metamon.level;
        if (level < 21) {
            needBalance += 10 * tear;
        } else if (21 <= level && level < 41) {
            needBalance += 10 * tear;
        } else {
            needBalance += 10 * tear;
        }
    }
    return balance >= needBalance;
}

AutoBattle.prototype.batchBattle = async function (tasks) {
    let self = this;
    
    return new Promise((resolve, reject) => {
        Promise.all(tasks).then((results)=> {
            console.log(">>>>>>>>>>>>>>>>>>>本轮战斗结束，结果统计<<<<<<<<<<<<<<<<<<<<<<");
            for (let i = 0; i < results.length; i++) {
                    let item = results[i];
                    if (item.code == 0) {
                        console.log("#元兽" + item.metamon.tokenId + "执行异常："+item.error);
                    } else {
                        console.log("#元兽" + item.metamon.tokenId + " 胜率：" + (item.rarito * 100.0).toFixed(1) + "%，总经验 " + item.totalExp + "，总蛋片数：" + item.totalBpFragmentNum + "，总药水数：" + item.totalBpPotionNum);
                    }
                    
             }
             resolve();
        }).catch(err => {
            console.log(err);
            reject(err);
        });
    });
}

let wait = ms => new Promise(resolve => setTimeout(resolve, ms));

AutoBattle.prototype.battle = async function (metamon) {
    let self = this;
    return new Promise(async function (resolve, reject) {
        try {
    let battleLevel = self.getBattleLevel(metamon);      
    let enemyId = self.config.enemyId;
    if (enemyId == 0) {
        let objects = await self.metamonApi.getBattleObjects(metamon.id, battleLevel);
        enemyId = objects[0].id;
    }
    // console.log("对手：宠物#"+enemyId);
    console.log("元兽#" + metamon.tokenId + "，品质：" + metamon.rarity + "，等级：" + metamon.level + "，能量：" + metamon.tear + "，战斗力：" + metamon.sca + "，经验：" + metamon.exp + "/" + metamon.expMax);
    let successCount = 0;
    let failCount = 0;
    let totalBpFragmentNum = 0;
    let totalExp = 0;
    let totalBpPotionNum = 0;
    let baseExp = metamon.exp;
    for (let i = 0; i < metamon.tear; i++) {
        // let isPay = await self.metamonApi.isPay(metamon.id, enemyId, battleLevel);
        // if (!isPay) {
        //     console.log("未检测到支付，请先充值或等待云服务器同步");
        //     return;
        // }
        /// 攻击
        let result = await self.metamonApi.battle(metamon.id, enemyId, battleLevel);
        let exp = result.challengeExp;
        let bpFragmentNum = result.bpFragmentNum;
        let bpPotionNum = result.bpPotionNum;
        // let battleResult = bpFragmentNum >= 24 ? "胜利" : "失败";
        let challengeRecords = result.challengeRecords;
        let battleResult = self.isVictory(metamon, challengeRecords) ? "胜利" : "失败";
        exp >= 5 ? successCount++ : failCount++;
        totalExp += exp;
        totalBpPotionNum += bpPotionNum;
        totalBpFragmentNum += bpFragmentNum;
        if (i + 1 < 10) {
            console.log("#元兽" + metamon.tokenId + " 第0" + (i + 1) + "战斗结果：" + battleResult + ", 获得经验：" + exp + "，蛋片：" + bpFragmentNum + "，药水：" + bpPotionNum);
        } else {
            console.log("#元兽" + metamon.tokenId + " 第" + (i + 1) + "战斗结果：" + battleResult + ", 获得经验：" + exp + "，蛋片：" + bpFragmentNum + "，药水：" + bpPotionNum);
        }
        /// 停顿0.3s, 防止服务器api安全策略报错
        await wait(300);
        /// 检测升级
        //if (baseExp + totalExp >= metamon.expMax && self.config.autoUpgrade == 1 && metamon.level > self.config.upgradeLevel && metamon.level < 60) {
        if (baseExp + totalExp >= 600 && self.config.autoUpgrade == 1 && metamon.level > self.config.upgradeLevel && metamon.level < 60) {
            let ps = await self.getNft(2);
            if (ps.bpNum <= 0) {
                console.log("检测到元兽#" + metamon.tokenId + "经验已满，但经验药水不足无法升级, 暂停攻击！");
                return;
            }
            console.log("检测到元兽经验已满，启动升级!");
            let result = await self.metamonApi.upgrade(metamon.id);
            if (result.result == 1) {
                console.log("元兽#"+metamon.tokenId+"升级成功!");
                baseExp = 0;
                /// 刷新等级
                if (metamon.level + 1 == 21) {
                    battleLevel = 2;
                } else if (metamon.level + 1 == 41) {
                    battleLevel = 3;
                }
                // if (metamon.level + 1 == 21 || metamon.level + 1 == 41) {
                //     metamon = await self.metamonApi.getMetamonInfo(metamon.id);
                //     battleLevel = self.getBattleLevel(metamon);
                // }
            } else {
                console.log("元兽#"+metamon.tokenId+"升级失败, 暂停攻击:" + result.message);
                return;
            }

        }
    }
    let rarito = (successCount / (successCount + failCount));
    resolve({
        code: 1,
        metamon: metamon,
        rarito: rarito,
        totalExp: totalExp,
        totalBpFragmentNum: totalBpFragmentNum,
        totalBpPotionNum: totalBpPotionNum
    });

        } catch (err) {
            console.log(err);
            resolve({
                code: 0,
                metamon: metamon,
                error: err
            });
        }
    });
    

}

AutoBattle.prototype.isVictory = function (metamon, challengeRecords) {
    let last = challengeRecords[challengeRecords.length - 1];
    let maId = last.monsteraId;
    let maLife = last.monsteraLife;
    if (maId == metamon.id) {
        return maLife > 0;
    } else {
        return maLife <= 0;
    }

}

AutoBattle.prototype.getBattleLevel = function (metamon) {
    let level = metamon.level;
    if (level < 21) {
        return 1;
    } else if (21 <= level && level < 41) {
        return 2;
    } else {
        return 3;
    }
}

/// 获取特定NFT
AutoBattle.prototype.getNft = async function (bpType) {
    let self = this;
    let nfts = await self.metamonApi.checkBag();
    let nft;
    for (let i = 0; i < nfts.length; i++) {
        let item = nfts[i];
        if (item.bpType == bpType) {
            nft = item;
            break;
        }
    }
    return nft;
}

/// 获取可进行攻击的宠物
AutoBattle.prototype.getEnableMetamon = async function (potions, count) {
    let self = this;
    let metamons = await self.metamonApi.getMetamonList();
    console.log("当前账户共有" + metamons.length + "只元兽");
    let enablaMetamon;
    let enableMetamons = [];
    let enableCount = 0;
    for (let i = 0; i < metamons.length; i++) {
        let item = metamons[i];

        // let properties = await self.metamonApi.getMetamonInfo(item.id);
        /// 升级
        if (item.exp >= item.expMax && self.config.autoUpgrade == 1 && item.level > self.config.upgradeLevel && item.lenght < 60) {
            if (potions.bpNum > 0) {
                console.log("检测到元兽#" + item.id + "可升级，启动升级!");
                let result = await self.metamonApi.upgrade(item.id);
                if (result.result == 1) {
                    console.log("元兽#" + item.id + "升级成功!");
                } else {
                    console.log("元兽升级失败:" + result.message);
                    continue;
                }
            } else {
                console.log("元兽#" + item.id + "经验已满，但经验药水不足无法升级");
                continue;
            }
        }

        if (item.tear > 0 && item.level < 60) {
            enablaMetamon = item;
            enableMetamons.push(item);
            enableCount++;
            if (enableCount == count || i == metamons.lenght - 1) break;
        }

    }
    return enableMetamons;
}

/// 获取敌人ID
AutoBattle.prototype.getEnemyId = async function () {
    let self = this;
    self.config.enemyId;
}

module.exports = AutoBattle;